import helper,{ isString } from "../../core/helper";
import { 
  conditionComputed, 
  dataSourceFilter, 
  isExpression,
  getTableItem,
  getBindFiledMaxLength 
} from "./utils"
let rowLen = 0,colLen = 0;
let dataSource = {};//数据集（dataDb）对应的数据（临时存放）
const cellsMap = new Map();//ri_ci:cell 所有cell
const rowLenInColMap = new Map();//ci:[rlen] 每一列对应的“已经增加”的行数,和对应的锚点riAnchor(暂时没用)
const ignoreCells = new Set();//ri_ci 忽略便利的cells
const checkIsOk = function(){
  return new Promise((reolve,reject)=>{
    setTimeout(()=>{
      reolve()
    },10)
  })
}
const createKey = function(ri,ci){
  rowLen = Math.max(rowLen,ri);
  colLen = Math.max(colLen,ci);
  return `${ri}_${ci}`;
}
//获取当前列，额外增加的行数
const getRowLenInColMapNum = function(cell,ci){
  if(!cell.merge || !cell.merge[1]){
    return (rowLenInColMap.get(ci) || [0])[0]
  }else{
    let maxNum = 0;
    for(let i = 0; i <= cell.merge[1]; i++){
      let nowData = rowLenInColMap.get(ci+i) || [0];
      maxNum = Math.max(maxNum,nowData[0])
    }
    //此步骤很重要，因为是colspan的，所以此中列的行数应该相同
    for(let i = 0; i <= cell.merge[1]; i++){
      rowLenInColMap.set(ci+i,[maxNum]);
    }
    return maxNum;
  }
}
//设置条件属性的style
const setCellCondition = function(cell){
  if(!cell.dataCondition)return;
  let { tableItem = {} } = cell;
  let {list,style} = cell.dataCondition;
  let isOk = true;
  list.forEach(item=>{
    let { type, table, code,value,op,join} = item;
    let result;
    if(type == 'cell'){
      result = conditionComputed(cell.text,value,op);
    }else{
      let beforeVal = tableItem[table]?(tableItem[table][code] || ''):'';
      result = conditionComputed(beforeVal,value,op);
    }
    if(isOk){
      switch(join){
        case 'and':
          isOk = isOk && result
          break;
        case 'or':
          isOk = isOk || result
          break;
      }
    }
  });

  if(isOk){
    let newStyle = {};
    style.background && (newStyle.background = style.background+'');
    style.color && (newStyle.color = style.color+'');
    newStyle.hide = (style.hide+'' == 'true')?true:false;
    cell.conditionStyle = newStyle;
  }
}
const setListMarkCell = function(realRi,ci,realCell){
  let newCell = {...realCell}
  return ()=>{
    let _rowLen = rowLen;
    let newAddRiLen = 0;
    for(let i = realRi; i <= _rowLen; i++){
      newCell.text = i-realRi+1;
      newCell.tableItem = getTableItem(dataSource,i-realRi);
      if(newCell.merge){
        newAddRiLen = (newCell.merge[0] + 1)*(i-realRi);
        setMergeCell(newAddRiLen+1,ci,newCell)
      }else{
        newAddRiLen = (i-realRi);
        setCell(i,ci,newCell)
      }
    }
    /**在MarkCell的时候会新增额外格子;
     (防止存在合并单元格的现象),因为是colspan的，所以此中列的行数应该相同
    */
    let nowRowLenInColMapData = rowLenInColMap.get(ci) || [0];
    for(let c = 0; c <= (newCell.merge?newCell.merge[1]:0); c++){
      rowLenInColMap.set(ci+c,[nowRowLenInColMapData[0]+newAddRiLen]);
    }  
  }
}
const setCell = function(ri,ci,cell){
  let key = createKey(ri,ci);
  let lastCell = cellsMap.get(key) || {};
  let newCell = {...lastCell,...cell};
  setCellCondition(newCell)
  cellsMap.set(key,newCell);
}
const setMergeCell = function(ri,ci,cell){
  let rLen = cell.merge[0],
      cLen = cell.merge[1];
  for(let r = 0; r <= rLen; r++){
    for(let c = 0; c <= cLen; c++){
      if(r === 0 && c ===0){
        rLen && (cell.rowspan = 1+rLen);
        cLen && (cell.colspan = 1+cLen);
        setCell(ri+r,ci+c,cell);
      }else{
        setCell(ri+r,ci+c,{hide:true})
      }
    }
  }
}
const setBindFiledCell = function(realRi,realCi,cell,dataItem){
  let bindFiledArr = cell.bindFiled.split('.');
  let newCell = {...cell};
  newCell.text = dataItem[bindFiledArr[1]];
  if(newCell.merge){
    setMergeCell(realRi,realCi,newCell);
  }else{
    setCell(realRi,realCi,newCell);
  }
}
const setExpressionCell = function(realRi,realCi,realCell,i = 0){
  let { expression } = realCell;
  let newCell = {...realCell};
  let expressionParams = [];
  expression.relationCells.forEach(cell=>{
    if(isString(cell)){
      expressionParams.push(JSON.parse(cell));
    }else if(cell.bindFiled){
      let bindFiledArr = cell.bindFiled.split('.');
      let dataList = (dataSource[bindFiledArr[0]] || [])[i] || {};
      expressionParams.push(dataList[bindFiledArr[1]] || '');
    }else{
      expressionParams.push(cell.text)
    }
  });
  newCell.text = expression.fun(expressionParams);
  if(newCell.merge){
    setMergeCell(realRi,realCi,newCell);
  }else{
    setCell(realRi,realCi,newCell)
  }
}

const setBindFiledCells = function(realRi,realCi,cell){
  let bindFiledArr = cell.bindFiled.split('.');
  let dataList = dataSource[bindFiledArr[0]];
  let newAddRiLen = 0;
  dataList.forEach((data,index)=>{
    let newRi = realRi+ index;
    if(cell.merge){
      newRi = realRi+(cell.merge[0]+1)*index;
      newAddRiLen = (cell.merge[0] + 1)*index;//因为没算第一个合并的个数，所以最后要加上cell.merge[0]
    }else{
      newAddRiLen = index;
    }
    cell.tableItem = getTableItem(dataSource,index);
    setBindFiledCell(newRi,realCi,cell,data);
  })
  /**在bindFiled的时候会新增额外格子;
   (防止存在合并单元格的现象),因为是colspan的，所以此中列的行数应该相同
  */
  let nowRowLenInColMapData = rowLenInColMap.get(realCi) || [0];
  for(let ci = 0; ci <= (cell.merge?cell.merge[1]:0); ci++){
    rowLenInColMap.set(realCi+ci,[nowRowLenInColMapData[0]+newAddRiLen]);
  }  
}
const setExpressionCells = function(realRi,realCi,realCell){
  let { expression } = realCell;
  let {isBind,relationCells} = expression;
  if(isBind){
    let maxLength = getBindFiledMaxLength(dataSource,relationCells);
    let newAddRiLen = 0;
    for(let i = 0; i < maxLength;i++){
      let newRi = realRi+ i;
      if(realCell.merge){
        newRi = realRi+(realCell.merge[0]+1)*i;
        newAddRiLen = (realCell.merge[0] + 1)*i;//因为没算第一个合并的个数，所以最后要加上cell.merge[0]
      }else{
        newAddRiLen = i;
      }
      realCell.tableItem = getTableItem(dataSource,i);
      setExpressionCell(newRi,realCi,realCell,i);
    }
    /**在bindFiled的时候会新增额外格子;
     (防止存在合并单元格的现象),因为是colspan的，所以此中列的行数应该相同
    */
    let nowRowLenInColMapData = rowLenInColMap.get(realCi) || [0];
    for(let ci = 0; ci <= (realCell.merge?realCell.merge[1]:0); ci++){
      rowLenInColMap.set(realCi+ci,[nowRowLenInColMapData[0]+newAddRiLen]);
    }  
  }else{
    setExpressionCell(realRi,realCi,realCell)
  } 
}
const setGroupCells = function(realRi,realCi,cell,tableData){
  let rLen = cell.group[0],
      cLen = cell.group[1];
  let isBindFiled = false;
  let isOk = false,i = 0;
  //在处理group的时候，首先把所有的cell起始位置统一
  let maxLen = 0;
  for(let ci = 0; ci <= cLen; ci++){
    let nowRowLenInColMapData = rowLenInColMap.get(realCi+ci) || [0];
    maxLen = Math.max(maxLen,nowRowLenInColMapData[0]);
  }
  for(let ri = 0;ri <= rLen;ri++){
    for(let ci = 0; ci <= cLen; ci++){
      ignoreCells.add(`${cell.ri+ri}_${cell.ci+ci}`);
      if(ri === 0){
        rowLenInColMap.set(realCi+ci,[maxLen]);
      }
    }
  }
  //处理cell
  while(!isOk){
    let isLastData = false;
    for(let r = 0; r <= rLen; r++){
      let cells = tableData.rows[cell.ri+r]['cells'];
      if(!cells)continue;
      for(let c = 0; c <= cLen; c++){
        if(!cells[realCi+c])continue;
        let nowRi = realRi+r+i*(rLen+1),
            nowCi = realCi+c;
        let nowCell = {...cells[nowCi],ri: nowRi,ci: nowCi};
        //是否是表达式
        let expression = isExpression(tableData,nowCell);
        if(nowCell.listMark){
          nowCell.text = i+1;
          nowCell.tableItem = getTableItem(dataSource,i);
          if(nowCell.merge){
            setMergeCell(nowRi,nowCi,nowCell)
          }else{
            setCell(nowRi,nowCi,nowCell)
          }
        }else if(nowCell.bindFiled){
          let bindFiledArr = nowCell.bindFiled.split('.');
          let dataList = dataSource[bindFiledArr[0]];
          isBindFiled = true;
          nowCell.tableItem = getTableItem(dataSource,i);
          setBindFiledCell(nowRi,nowCi,nowCell,dataList[i]);
          if(!dataList[i+1]){//第一个数据集没了，就算结束
            isLastData = true;
          }
        }else if(expression){
          nowCell.expression = expression;
          nowCell.tableItem = getTableItem(dataSource,i);
          setExpressionCell(nowRi,nowCi,nowCell,i)
        }else if(nowCell.merge){
          setMergeCell(nowRi,nowCi,nowCell);
        }else{
          setCell(nowRi,nowCi,nowCell)
        }
      }
    }
    i++;
    if(!isBindFiled || isLastData){
      isOk = true;
    }
  }
  //更新nowRowLenInColMapData
  let nowRowLenInColMapData = rowLenInColMap.get(realCi) || [0];
  for(let ci = 0; ci <= cLen; ci++){
    rowLenInColMap.set(realCi+ci,[nowRowLenInColMapData[0]+(i-1)*(rLen+1)]);
  }
}
export async function getTable(tableData,_dataSource){
  const newData = helper.cloneDeep(tableData);
  const {rows} = newData;
  dataSource = dataSourceFilter(_dataSource,newData.dataFilter);
  cellsMap.clear();
  rowLenInColMap.clear();
  ignoreCells.clear();
  rowLen = 0;
  colLen = 0;
  //遍历所有cells
  for(let ri in rows){
    let cells = rows[ri]['cells'];
    let hasMarkCell = false;
    if(!cells)continue;
    ri = +ri;
    for(let ci in cells){
      if(!cells[ci])continue;
      if(ignoreCells.has(`${ri}_${ci}`))continue;
      ci = +ci;
      //真正的ri
      let rowLenInColMapNum = getRowLenInColMapNum(cells[ci],ci);
      let realRi = ri + rowLenInColMapNum;
      let realCell = {...cells[ci],ri,ci};
      //是否是表达式
      let expression = isExpression(newData,realCell);
      if(realCell.group){
        setGroupCells(realRi,ci,realCell,newData);
      }else if(realCell.listMark){//mark序号，只有当前行的所有列渲染完成之后，才知道长度。所以要放在此行所有cell读取之后执行
        hasMarkCell = setListMarkCell(realRi,ci,realCell)
      }else if(realCell.bindFiled){
        setBindFiledCells(realRi,ci,realCell)
      }else if(expression){
        realCell.expression = expression;
        setExpressionCells(realRi,ci,realCell,newData)
      }else if(realCell.merge){
        setMergeCell(realRi,ci,realCell)
      }else{
        setCell(realRi,ci,realCell)
      }
    }
    hasMarkCell && hasMarkCell();
    hasMarkCell = false;
  }
  await checkIsOk();
  return Promise.resolve({cellsMap,rowLen,colLen})
}

export function setText(tdDom,cell){
  if(!cell)return;
  tdDom.html(cell.text);
}
export function setConditionStyle(tdDom,cell){
  if(!cell || !cell.conditionStyle)return;
  let conditionStyle = cell.conditionStyle;
  if(conditionStyle.hide){
    tdDom.html('')
  }
  delete conditionStyle.hide;
  tdDom.css(conditionStyle)
}
export function setStyle(tdDom,cell){
  if(!cell || !(cell.style+''))return;
  let cellStyle = this.sheetData.styles[cell.style];
  let style = {};
  for(let key in cellStyle){
    let value = cellStyle[key];
    switch(key){
      case 'bgcolor':
        style.background = value;
        break;
      case 'align':
        style.textAlign = value;
        break;
      case 'valign':
        style.verticalAlign = value;
        break;
      case 'textwrap':
        if(value){
          style.wordBreak = 'break-all'
        }
        break;
      case 'strike':
        if(value){
          style.textDecoration = 'line-through';
        }
        break;
      case 'underline':
        if(value){
          style.textDecoration = 'underline';
        }
        break;
      case 'color':
        style.color = value;
        break;
      case 'font':
        value.name && (style.fontFamily = value.name);
        value.bold && (style.fontWeight = 600);
        value.size && (style.fontSize = value.size+'px');
        value.italic &&　(style.fontStyle = 'italic')
        break;
      case 'border':
        let arr = ['thin','medium','thick'];
        if(value.top){
          let type = arr.indexOf(value.top[0])!=-1?'solid':value.top[0];
          style.borderTop = `1px ${type} ${value.top[1]}`
        }
        if(value.right){
          let type = arr.indexOf(value.right[0])!=-1?'solid':value.right[0];
          style.borderRight = `1px ${type} ${value.right[1]}`
        }
        if(value.bottom){
          let type = arr.indexOf(value.bottom[0])!=-1?'solid':value.bottom[0];
          style.borderBottom = `1px ${type} ${value.bottom[1]}`
        }
        if(value.left){
          let type = arr.indexOf(value.left[0])!=-1?'solid':value.left[0];
          style.borderLeft = `1px ${type} ${value.left[1]}`
        }
        break;
    }
  }
  tdDom.css(style)
}
export function setMerge(tdDom,cell){
  if(!cell)return;
  cell.rowspan && tdDom.attr('rowspan',cell.rowspan)
  cell.colspan && tdDom.attr('colspan',cell.colspan)
  cell.hide && tdDom.hide()
}